﻿using Hsp.Auto.Common.Data;
using System;
using System.Configuration;

namespace Hsp.Auto.Console
{
    /// <summary>
    /// Asp.Net Core NuGet引用SQLite
    /// System.Data.SQLite.Core
    /// V1.0.115.5
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            //System.Console.WriteLine("Hello World!");

            var type = DBType.SqlServer;
            type = DBType.SQLite;
            var connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ToString();
            if (type == DBType.SQLite)
            {
                Hsp.Auto.SQLite.DataHelper.SetConnectionString(connectionString);
            }

            string sql = "select * from DbConfigs order by Modified desc";

            System.Console.WriteLine("枚举成员的名称:{0}", type);
            System.Console.WriteLine("枚举成员的数值：{0}", Convert.ToInt16(type));

            //{
            //    ITableService service = new TableService();
            //    //IDbHelper service = new SqlServerHelper();
            //    //ITableService dbHelper = (ITableService)(new Hsp.Auto.SQLite.TableService());
            //    //ITableService dbHelper = SimpleFactory.CreateInstance<TableService>();

            //    ITableService dbHelper = SimpleFactory.CreateInstance<ITableService>(type, "TableService");

            //    List<DbConfigs> list = dbHelper.ListQuery<DbConfigs>();
            //    System.Console.WriteLine(list.Count);

            //    foreach (var config in list)
            //    {
            //        System.Console.WriteLine(config.ConnString);
            //    }
            //}

            //{
            //    IDbHelper dbHelper = SimpleFactory.CreateInstance(type);
            //    List<DbConfigs> list = dbHelper.ListQuery<DbConfigs>();
            //    System.Console.WriteLine(list.Count);

            //    foreach (var config in list)
            //    {
            //        System.Console.WriteLine(config.ConnString);
            //    }
            //}

            //{
            //    using var connection = new SQLiteConnection(connectionString);
            //    connection.Open();

            //    var d = connection;
            //    SQLiteCommand cmd;
            //    SQLiteDataReader dr;

            //    cmd = new SQLiteCommand(sql, connection);
            //    dr = cmd.ExecuteReader();
            //    while (dr.Read())
            //    {
            //        string strToPrint;

            //        strToPrint = string.Format("{0}||{1}<br/>", dr[0].ToString(), dr[1].ToString());

            //        System.Console.WriteLine(strToPrint);
            //    }
            //}

            //{
            //    using var connection = new SQLiteConnection(connectionString);
            //    connection.Open();

            //    DataSet ds = new DataSet("ds");

            //    try
            //    {
            //        //SQLiteDataAdapter adapter = new SQLiteDataAdapter();
            //        SQLiteDataAdapter da = new SQLiteDataAdapter(sql, connection);
            //        //DataSet ds = new DataSet();
            //        da.Fill(ds);
            //    }
            //    catch (Exception ex)
            //    {
            //        throw ex;
            //    }
            //    finally
            //    {
            //        connection?.Close();
            //    }

            //    DataTable dt = null;
            //    if (ds != null && ds.Tables.Count > 0)
            //    {
            //        dt = ds.Tables[0];
            //        dt.TableName = "data";
            //    }
            //}

            {
                // 雪花算法

                // 概述
                // 分布式系统中，有一些需要使用全局唯一ID的场景，这种时候为了防止ID冲突可以使用36位的UUID，
                // 但是UUID有一些缺点，首先他相对比较长，另外UUID一般是无序的。有些时候我们希望能使用一种
                // 简单一些的ID，并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求，
                // 最初Twitter把存储系统从MySQL迁移到Cassandra，因为Cassandra没有顺序ID生成机制，
                // 所以开发了这样一套全局唯一ID生成服务。
                // 该项目地址为：https://github.com/twitter/snowflake是用Scala实现的。 

                // 结构
                // snowflake的结构如下(每部分用 - 分开):

                // 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000

                // 1 位标识，0表示正数。
                // 41 位时间戳，当前时间的毫秒减去开始时间的毫秒数。可用(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年。
                // 5 位数据中心标识，可支持(1L << 5) = 32个数据中心。
                // 5 位机器标识，每个数据中心可支持(1L << 5) = 32个机器标识。
                // 12 位序列号，每个节点每一毫秒支持(1L << 12) = 4096个序列号。

                // 第一位为未使用，接下来的41位为毫秒级时间(41位的长度可以使用69年)，
                // 然后是5位datacenterId和5位workerId(10位的长度最多支持部署1024个节点），
                // 最后12位是毫秒内的计数（12位的计数顺序号支持每个节点每毫秒产生4096个ID序号）

                //一共加起来刚好64位，为一个Long型。(转换成字符串长度为18)
                //snowflake生成的ID整体上按照时间自增排序，并且整个分布式系统内不会产生ID碰撞
                // （由datacenter和workerId作区分），并且效率较高。据说：snowflake每秒能够产生26万个ID。

                //IdWorker idworker = new IdWorker(1);
                //for (int i = 0; i < 1000; i++)
                //{
                //    System.Console.WriteLine(idworker.nextId());
                //}
            }

            {
                //Pluralizer _pluralizer = new Pluralizer(); // 单复数服务实例
                //var word = "AuthUsers";
                //var rst = _pluralizer.Singularize(word);
                //System.Console.WriteLine($"{word}->{rst}");

                //word = "AuthRoles";
                //rst = _pluralizer.Singularize(word);
                //System.Console.WriteLine($"{word}->{rst}");

                //word = "AuthMenus";
                //rst = _pluralizer.Singularize(word);
                //System.Console.WriteLine($"{word}->{rst}");

            }



            System.Console.ReadKey();
        }






    }

    public class IdWorker
    {
        //机器ID
        private static long workerId;
        private static long twepoch = 687888001020L; //唯一时间，这是一个避免重复的随机量，自行设定不要大于当前时间戳
        private static long sequence = 0L;
        private static int workerIdBits = 4; //机器码字节数。4个字节用来保存机器码(定义为Long类型会出现，最大偏移64位，所以左移64位没有意义)
        public static long maxWorkerId = -1L ^ -1L << workerIdBits; //最大机器ID
        private static int sequenceBits = 10; //计数器字节数，10个字节用来保存计数码
        private static int workerIdShift = sequenceBits; //机器码数据左移位数，就是后面计数器占用的位数
        private static int timestampLeftShift = sequenceBits + workerIdBits; //时间戳左移动位数就是机器码和计数器总字节数
        public static long sequenceMask = -1L ^ -1L << sequenceBits; //一微秒内可以产生计数，如果达到该值则等到下一微妙在进行生成
        private long lastTimestamp = -1L;

        /// <summary>
        /// 机器码
        /// </summary>
        /// <param name="workerId"></param>
        public IdWorker(long workerId)
        {
            if (workerId > maxWorkerId || workerId < 0)
                throw new Exception(string.Format("worker Id can't be greater than {0} or less than 0 ", workerId));
            IdWorker.workerId = workerId;
        }

        public long nextId()
        {
            lock (this)
            {
                long timestamp = timeGen();
                if (this.lastTimestamp == timestamp)
                { //同一微妙中生成ID
                    IdWorker.sequence = (IdWorker.sequence + 1) & IdWorker.sequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限
                    if (IdWorker.sequence == 0)
                    {
                        //一微妙内产生的ID计数已达上限，等待下一微妙
                        timestamp = tillNextMillis(this.lastTimestamp);
                    }
                }
                else
                { //不同微秒生成ID
                    IdWorker.sequence = 0; //计数清0
                }
                if (timestamp < lastTimestamp)
                { //如果当前时间戳比上一次生成ID时时间戳还小，抛出异常，因为不能保证现在生成的ID之前没有生成过
                    throw new Exception(string.Format("Clock moved backwards.  Refusing to generate id for {0} milliseconds",
                        this.lastTimestamp - timestamp));
                }
                this.lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
                long nextId = (timestamp - twepoch << timestampLeftShift) | IdWorker.workerId << IdWorker.workerIdShift | IdWorker.sequence;
                return nextId;
            }
        }

        /// <summary>
        /// 获取下一微秒时间戳
        /// </summary>
        /// <param name="lastTimestamp"></param>
        /// <returns></returns>
        private long tillNextMillis(long lastTimestamp)
        {
            long timestamp = timeGen();
            while (timestamp <= lastTimestamp)
            {
                timestamp = timeGen();
            }
            return timestamp;
        }

        /// <summary>
        /// 生成当前时间戳
        /// </summary>
        /// <returns></returns>
        private long timeGen()
        {
            return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
        }
    }
}
